package roaring

import (
	
)

// Or function that requires repairAfterLazy
func lazyOR(,  *Bitmap) *Bitmap {
	 := NewBitmap()
	 := 0
	 := 0
	 := .highlowcontainer.size()
	 := .highlowcontainer.size()
:
	for ( < ) && ( < ) {
		 := .highlowcontainer.getKeyAtIndex()
		 := .highlowcontainer.getKeyAtIndex()

		for {
			if  <  {
				.highlowcontainer.appendCopy(.highlowcontainer, )
				++
				if  ==  {
					break 
				}
				 = .highlowcontainer.getKeyAtIndex()
			} else if  >  {
				.highlowcontainer.appendCopy(.highlowcontainer, )
				++
				if  ==  {
					break 
				}
				 = .highlowcontainer.getKeyAtIndex()
			} else {
				 := .highlowcontainer.getContainerAtIndex()
				.highlowcontainer.appendContainer(, .lazyOR(.highlowcontainer.getContainerAtIndex()), false)
				++
				++
				if ( == ) || ( == ) {
					break 
				}
				 = .highlowcontainer.getKeyAtIndex()
				 = .highlowcontainer.getKeyAtIndex()
			}
		}
	}
	if  ==  {
		.highlowcontainer.appendCopyMany(.highlowcontainer, , )
	} else if  ==  {
		.highlowcontainer.appendCopyMany(.highlowcontainer, , )
	}
	return 
}

// In-place Or function that requires repairAfterLazy
func ( *Bitmap) ( *Bitmap) *Bitmap {
	 := 0
	 := 0
	 := .highlowcontainer.size()
	 := .highlowcontainer.size()
:
	for ( < ) && ( < ) {
		 := .highlowcontainer.getKeyAtIndex()
		 := .highlowcontainer.getKeyAtIndex()

		for {
			if  <  {
				++
				if  ==  {
					break 
				}
				 = .highlowcontainer.getKeyAtIndex()
			} else if  >  {
				.highlowcontainer.insertNewKeyValueAt(, , .highlowcontainer.getContainerAtIndex().clone())
				++
				++
				++
				if  ==  {
					break 
				}
				 = .highlowcontainer.getKeyAtIndex()
			} else {
				 := .highlowcontainer.getWritableContainerAtIndex()
				.highlowcontainer.containers[] = .lazyIOR(.highlowcontainer.getContainerAtIndex())
				.highlowcontainer.needCopyOnWrite[] = false
				++
				++
				if ( == ) || ( == ) {
					break 
				}
				 = .highlowcontainer.getKeyAtIndex()
				 = .highlowcontainer.getKeyAtIndex()
			}
		}
	}
	if  ==  {
		.highlowcontainer.appendCopyMany(.highlowcontainer, , )
	}
	return 
}

// to be called after lazy aggregates
func ( *Bitmap) () {
	for  := 0;  < .highlowcontainer.size(); ++ {
		 := .highlowcontainer.getContainerAtIndex()
		switch .(type) {
		case *bitmapContainer:
			if .(*bitmapContainer).cardinality == invalidCardinality {
				 = .highlowcontainer.getWritableContainerAtIndex()
				.(*bitmapContainer).computeCardinality()
				if .(*bitmapContainer).getCardinality() <= arrayDefaultMaxSize {
					.highlowcontainer.setContainerAtIndex(, .(*bitmapContainer).toArrayContainer())
				} else if .(*bitmapContainer).isFull() {
					.highlowcontainer.setContainerAtIndex(, newRunContainer16Range(0, MaxUint16))
				}
			}
		}
	}
}

// FastAnd computes the intersection between many bitmaps quickly
// Compared to the And function, it can take many bitmaps as input, thus saving the trouble
// of manually calling "And" many times.
//
// Performance hints: if you have very large and tiny bitmaps,
// it may be beneficial performance-wise to put a tiny bitmap
// in first position.
func ( ...*Bitmap) *Bitmap {
	if len() == 0 {
		return NewBitmap()
	} else if len() == 1 {
		return [0].Clone()
	}
	 := And([0], [1])
	for ,  := range [2:] {
		.And()
	}
	return 
}

// FastOr computes the union between many bitmaps quickly, as opposed to having to call Or repeatedly.
// It might also be faster than calling Or repeatedly.
func ( ...*Bitmap) *Bitmap {
	if len() == 0 {
		return NewBitmap()
	} else if len() == 1 {
		return [0].Clone()
	}
	 := lazyOR([0], [1])
	for ,  := range [2:] {
		 = .lazyOR()
	}
	// here is where repairAfterLazy is called.
	.repairAfterLazy()
	return 
}

// HeapOr computes the union between many bitmaps quickly using a heap.
// It might be faster than calling Or repeatedly.
func ( ...*Bitmap) *Bitmap {
	if len() == 0 {
		return NewBitmap()
	}
	// TODO:  for better speed, we could do the operation lazily, see Java implementation
	 := make(priorityQueue, len())
	for ,  := range  {
		[] = &item{, }
	}
	heap.Init(&)

	for .Len() > 1 {
		 := heap.Pop(&).(*item)
		 := heap.Pop(&).(*item)
		heap.Push(&, &item{Or(.value, .value), 0})
	}
	return heap.Pop(&).(*item).value
}

// HeapXor computes the symmetric difference between many bitmaps quickly (as opposed to calling Xor repeated).
// Internally, this function uses a heap.
// It might be faster than calling Xor repeatedly.
func ( ...*Bitmap) *Bitmap {
	if len() == 0 {
		return NewBitmap()
	}

	 := make(priorityQueue, len())
	for ,  := range  {
		[] = &item{, }
	}
	heap.Init(&)

	for .Len() > 1 {
		 := heap.Pop(&).(*item)
		 := heap.Pop(&).(*item)
		heap.Push(&, &item{Xor(.value, .value), 0})
	}
	return heap.Pop(&).(*item).value
}

// AndAny provides a result equivalent to x1.And(FastOr(bitmaps)).
// It's optimized to minimize allocations. It also might be faster than separate calls.
func ( *Bitmap) ( ...*Bitmap) {
	if len() == 0 {
		return
	} else if len() == 1 {
		.And([0])
		return
	}

	type  struct {
		 *roaringArray
		    int
		    uint16
	}
	 := make([], 0, len())

	for ,  := range  {
		if .highlowcontainer.size() > 0 {
			 = append(, {
				: &.highlowcontainer,
				:    0,
				:    .highlowcontainer.getKeyAtIndex(0),
			})
		}
	}

	 := 0
	 := 0
	 := make([]container, 0, len())
	var (
		   *arrayContainer
		  *bitmapContainer
		 uint16
	)

	for  < .highlowcontainer.size() && len() > 0 {
		 := .highlowcontainer.getKeyAtIndex()

		// accumulate containers for current key, find next minimal key in filters
		// and exclude filters that do not have related values anymore
		 := 0
		 := 0
		 = MaxUint16
		for ,  := range  {
			if . <  {
				. = ..advanceUntil(, .)
				if . == ..size() {
					continue
				}
				. = ..getKeyAtIndex(.)
			}

			if . ==  {
				 := ..getContainerAtIndex(.)
				 = append(, )
				 += .getCardinality()

				.++
				if . == ..size() {
					continue
				}
				. = ..getKeyAtIndex(.)
			}

			 = minOfUint16(, .)
			[] = 
			++
		}
		 = [:]

		if len() == 0 {
			 = .highlowcontainer.advanceUntil(, )
			continue
		}

		var  container

		if len() == 1 {
			 = [0]
		} else {
			//TODO: special case for run containers?
			if  > arrayDefaultMaxSize {
				if  == nil {
					 = newBitmapContainer()
				}
				.resetTo([0])
				 = 
			} else {
				if  == nil {
					 = newArrayContainerCapacity()
				}
				.realloc()
				.resetTo([0])
				 = 
			}
			for ,  := range [1:] {
				 = .ior()
			}
		}

		 := .highlowcontainer.getWritableContainerAtIndex().iand()
		if !.isEmpty() {
			.highlowcontainer.replaceKeyAndContainerAtIndex(, , , false)
			++
		}

		 = [:0]
		 = .highlowcontainer.advanceUntil(, )
	}

	.highlowcontainer.resize()
}